#ifndef TREESITTER_H_
#define TREESITTER_H_

#include <QDebug>
#include <QFile>
#include <QProcess>
#include <QString>
#include <QStringList>
#include <QTemporaryDir>
#include <QTextStream>
#include <qchar.h>

struct PyMsg {
  QString msg;
  bool error = false;
};

class TreeSitterSelect {
public:
  TreeSitterSelect();
  ~TreeSitterSelect();
  PyMsg execute(const QStringList &args);
  void setPythonBinPath(QString path);

private:
  QTemporaryDir *tempDir;
  QString pythonBinPath = "python";
  QString pythonScriptPath;
  QString pythonScript = R"(from tree_sitter import Language, Parser
from pathlib import Path
import importlib
import argparse


def get_tree_sitter_language(file_extension):
    """
    根据文件扩展名动态导入 tree-sitter 模块并返回解析器语言
    """
    language_map = {
        "py": "tree_sitter_python",
        "c": "tree_sitter_c",
        "js": "tree_sitter_javascript",
        "cpp": "tree_sitter_cpp",
        "h": "tree_sitter_cpp",
    }

    module_name = language_map.get(file_extension)
    if not module_name:
        raise ValueError(f"Unsupported file extension: {file_extension}")

    # 动态导入模块
    tree_sitter_module = importlib.import_module(module_name)

    # 返回语言对象
    return Language(tree_sitter_module.language())


# 定义函数
class SyntaxSelector:
    def __init__(self, code_file_path):
        file_extension = code_file_path.split(".")[-1]
        LANGUAGE = get_tree_sitter_language(file_extension)
        source_code = Path(code_file_path).read_text(encoding="utf-8")

        self.parser = Parser(LANGUAGE)
        self.source_code = source_code
        self.tree = self.parser.parse(bytes(source_code, "utf8"))

    def find_node_range(self, node_type, cursor_position):
        """
        查找与给定光标位置相符的语法节点范围。
        :param node_type: 想要选择的节点类型（如 'function_definition', 'block', 'expression' 等）。
        :param cursor_position: 光标当前位置，元组 (line, column)。
        :return: 起始和结束位置 (start, end)。
        """
        cursor = self.tree.walk()
        selected_node = None

        for node in self._walk(cursor):
            start_pos = node.start_point
            end_pos = node.end_point
            if node.type == node_type and self._is_cursor_in_range(
                cursor_position, start_pos, end_pos
            ):
                selected_node = node
                break

        if selected_node:
            return (
                selected_node.start_point,
                selected_node.end_point,
                selected_node.start_byte,
                selected_node.end_byte,
            )
        else:
            return None

    def get_all_containing_nodes(self, cursor_position):
        """
        返回光标位置所在的所有节点的类型和范围。
        """
        cursor = self.tree.walk()
        containing_nodes = []

        for node in self._walk(cursor):
            start_pos = node.start_point
            end_pos = node.end_point
            start_byte = node.start_byte
            end_byte = node.end_byte
            if self._is_cursor_in_range(cursor_position, start_pos, end_pos):
                containing_nodes.append(
                    {
                        "node_type": node.type,
                        "start_pos": start_pos,
                        "end_pos": end_pos,
                        "start_byte": start_byte,
                        "end_byte": end_byte,
                    }
                )

        return containing_nodes

    def _walk(self, cursor):
        """
        遍历语法树节点。
        """
        reached_root = False
        while not reached_root:
            yield cursor.node
            if cursor.goto_first_child():
                continue
            if cursor.goto_next_sibling():
                continue
            while not cursor.goto_next_sibling():
                if not cursor.goto_parent():
                    reached_root = True
                    break

    def _is_cursor_in_range(self, cursor_position, start_pos, end_pos):
        """
        检查光标是否在节点范围内。
        """
        (cursor_line, cursor_col) = cursor_position
        (start_line, start_col) = start_pos
        (end_line, end_col) = end_pos

        return (
            cursor_line > start_line
            or (cursor_line == start_line and cursor_col >= start_col)
        ) and (
            cursor_line < end_line
            or (cursor_line == end_line and cursor_col <= end_col)
        )


def getCodeRangeContent(code, start, end):
    code = code.split("\n")
    code = code[start.row : end.row + 1]
    if len(code) > 1:
        code[0] = code[0][start.column :]
        code[-1] = code[-1][: end.column]
    else:
        code[0] = code[0][start.column : end.column]
    return "\n".join(code)


# 示例使用
if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="tree sitter select node command-line tool."
    )
    parser.add_argument("code_file_path", help="parse file path")
    parser.add_argument("-r", "--row", type=int, help="cursor row")
    parser.add_argument("-c", "--col", type=int, help="cursor column")
    parser.add_argument(
        "-e",
        "--exclude",
        type=int,
        help="exclude node for length smaller than this",
        default=0,
    )

    args = parser.parse_args()

    selector = SyntaxSelector(args.code_file_path)
    code = selector.source_code

    cursor_pos = (args.row, args.col)

    result = selector.get_all_containing_nodes(cursor_pos)

    if result:
        for node in reversed(result):
            node_length = node["end_byte"] - node["start_byte"]
            if node_length > args.exclude:
                start_pos = node["start_pos"]
                end_pos = node["end_pos"]
                start_byte = node["start_byte"]
                end_byte = node["end_byte"]
                print(
                    start_pos.row,
                    start_pos.column,
                    end_pos.row,
                    end_pos.column,
                    start_byte,
                    end_byte,
                )
                break
)";
};
#endif // TREESITTER_H_

